package com.king.utils;

import org.dom4j.*;
import org.dom4j.io.SAXReader;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * 通用工具类
 */
public class CommonUtils {

    public static final String DEF_CHATSET = "UTF-8";
    public static final int DEF_CONN_TIMEOUT = 30000;
    public static final int DEF_READ_TIMEOUT = 30000;
    public static String userAgent =  "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";

    /**
     * 对象是否为空
     *
     * @param obj
     * @return
     */
    public static boolean isNullOrEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        return false;
    }

    /**
     * 判断整数是否大于零
     *
     * @param number
     * @return
     */
    public static boolean isIntThanZero(int number) {
        if (number > 0) {
            return true;
        }
        return false;
    }

    /**
     * SQL模糊查询特殊字符转义(%,_)
     *
     * @param keyword
     * @return
     */
    public static String fixSpecialForLike(String keyword) {
        if (StringUtils.isNotBlank(keyword)) {
            char[] keys = keyword.toCharArray();
            StringBuilder sb = new StringBuilder();
            for (char key : keys) {
                if (key == '%' || key == '_') {
                    sb.append('\\');
                }
                sb.append(key);
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * SQL模糊查询特殊字符转义
     *
     * @param params 参数map
     * @param keys   需要转义的参数key
     * @return
     */
    public static Map<String, Object> fixSpecialForLike(Map<String, Object> params, String... keys) {
        if (keys.length == 0) {
            return params;
        }
        for (String key : keys) {
            Object value = params.get(key);
            if (value != null) {
                params.put(key, fixSpecialForLike(String.valueOf(value)));
            }
        }
        return params;
    }

    /**
     * 进行sha1加密（摘要加密算法）
     *
     * @param src
     * @return
     */
    public static String sha1(String src) {
        try {
            MessageDigest md = MessageDigest.getInstance("sha1");
            byte[] digest = md.digest(src.getBytes());
            char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(chars[(b >> 4) & 15]);
                sb.append(chars[b & 15]);
            }
            return sb.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 解析请求数据
     *
     * @param is
     * @return
     */
    public static Map<String, String> parseRequest(InputStream is) throws Exception {
        HashMap<String, String> requestMap = new HashMap<>();
        SAXReader sax = new SAXReader();
        Document document = sax.read(is);
        Element rootElement = document.getRootElement();
        List<Element> elements = rootElement.elements();
        for (Element e : elements) {
            requestMap.put(e.getName(), e.getStringValue());
        }
        return requestMap;
    }

    /**
     * xml 转 map
     * @param is
     * @return
     */
    public static Map<String, Object> xml2MapByStream(InputStream is) throws Exception {
        SAXReader sax = new SAXReader();
        Document doc = sax.read(is);
        Element rootElement = doc.getRootElement();
        Map<String, Object> map = new HashMap();
        ele2map(map, rootElement);
        return map;
    }

    /**
     * xml 转 map
     * @param xmlStr
     * @return
     * @throws DocumentException
     */
    public static Map<String, Object> xml2MapByXmlStr(String xmlStr) throws DocumentException {
        Document doc = DocumentHelper.parseText(xmlStr);
        Element rootElement = doc.getRootElement();
        Map<String, Object> map = new HashMap();
        ele2map(map, rootElement);
        return map;
    }

    private static void ele2map(Map<String, Object> map, Element ele) {
        // 获得当前节点的子节点
        List<Element> elements = ele.elements();
        if (elements.size() == 0) {
            // 没有子节点说明当前节点是叶子节点，直接取值即可
            String val = ele.getText();
            if (!StringUtils.isEmpty(val)) {
                map.put(ele.getName(), val);
            }
        } else if (elements.size() == 1) {
            // 只有一个子节点说明不用考虑list的情况，直接继续递归即可
            Map<String, Object> tempMap = new HashMap<String, Object>();
            ele2map(tempMap, elements.get(0));
            map.put(ele.getName(), tempMap);
        } else {
            // 多个子节点的话就得考虑list的情况了，比如多个子节点有节点名称相同的
            // 构造一个map用来去重
            Map<String, Object> tempMap = new HashMap<String, Object>();
            for (Element element : elements) {
                tempMap.put(element.getName(), null);
            }
            Set<String> keySet = tempMap.keySet();
            for (String string : keySet) {
                Namespace namespace = elements.get(0).getNamespace();
                List<Element> elements2 = ele.elements(new QName(string, namespace));
                // 如果同名的数目大于1则表示要构建list
                if (elements2.size() > 1) {
                    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                    for (Element element : elements2) {
                        Map<String, Object> tempMap1 = new HashMap<String, Object>();
                        ele2map(tempMap1, element);
                        list.add(tempMap1);
                    }
                    map.put(string, list);
                } else {
                    // 同名的数量不大于1则直接递归去
                    Map<String, Object> tempMap1 = new HashMap<String, Object>();
                    ele2map(tempMap1, elements2.get(0));

//                    String kry = (String) tempMap1.get(string);
//                    //如果是空的 会是list节点
//                    if(StringUtils.isEmpty(kry)){
//                        map.put(string, tempMap1);
//                    }else{
//                        map.put(string, kry);
//                    }

                    Object kry = tempMap1.get(string);
                    if(kry instanceof String){
                        kry = kry.toString();
                    }else if(kry == null){
                        kry = tempMap1;
                    }
                    map.put(string, kry);
                }
            }
        }
    }

    /**
     * 向指定URL发起GET请求
     *
     * @param urlStr
     * @return
     */
    public static String get(String urlStr) {
        URL url = null;
        URLConnection connection = null;
        try {
            url = new URL(urlStr);
            connection = url.openConnection();
            InputStream stream = connection.getInputStream();

            StringBuilder sb = new StringBuilder();
            byte[] b = new byte[1024];
            int len;
            while ((len = stream.read(b)) != -1) {
                sb.append(new String(b, 0, len));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 向指定URL发起POST请求
     *
     * @param urlStr
     * @return
     */
    public static String post(String urlStr, String data) {
        try {
            URL url = new URL(urlStr);
            URLConnection connection = url.openConnection();

            connection.setDoOutput(true);
            OutputStream outputStream = connection.getOutputStream();
            outputStream.write(data.getBytes());
            outputStream.close();

            StringBuilder sb = new StringBuilder();
            InputStream inputStream = connection.getInputStream();
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b)) != -1) {
                sb.append(new String(b, 0, len));
            }
            inputStream.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 上传文件
     * @param urlStr
     * @param filePath
     * @return
     */
    public static String uploadFile(String urlStr,String filePath) {
        try {
            File file = new File(filePath);

            URL url = new URL(urlStr);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();//强转为安全连接

            //设置链接的信息
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            //设置请求头信息
            conn.setRequestProperty("Connection","Keep-Alive");
            conn.setRequestProperty("Charset","utf8");
            String boundary = "-----"+System.currentTimeMillis();   //设置数据的边界
            conn.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);

            //输出流,写出数据
            OutputStream out = conn.getOutputStream();

            //设置请求数据
            //1.头部信息
            StringBuilder sbHeader = new StringBuilder();
            sbHeader.append("--");
            sbHeader.append(boundary);
            sbHeader.append("\r\n");
            sbHeader.append("Content-Disposition:form-data;name=\"media\";filename=\""+file.getName()+"\"");
            sbHeader.append("Content-Type:application/octet-stream\r\n\r\n");
            out.write(sbHeader.toString().getBytes());
            //2.文件内容
            InputStream is = new FileInputStream(file);//文件的输入流
            byte[] data = new byte[1024];
            int length;
            while ((length=is.read(data))!=-1){
                out.write(data,0,length);
            }
            is.close();
            //3.尾部信息
            String foot = "\r\n--"+boundary+"--\r\n";
            out.write(foot.getBytes());

            out.flush();
            out.close();

            //读取数据
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = conn.getInputStream();
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b)) != -1) {
                sb.append(new String(b, 0, len));
            }
            inputStream.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String sendHttpsPost(String url, String params, String method) throws Exception{
        URL myurl = new URL(url);
        HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();

        con.setRequestMethod(method);
        if(StringUtils.isNotBlank(params)){
            con.setRequestProperty("Content-length", String.valueOf(params.length()));
        }

        con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
        con.setRequestProperty("Charset","utf8");

        con.setDoOutput(true);
        con.setDoInput(true);

        if(StringUtils.isNotBlank(params)) {
            DataOutputStream output = new DataOutputStream(con.getOutputStream());
            output.writeBytes(params);
            output.close();
        }

        StringBuilder sb = new StringBuilder();
        DataInputStream input = new DataInputStream( con.getInputStream());
        byte[] b = new byte[1024];
        int len=0;
        while ((len = input.read(b))!=-1){
            sb.append(new String(b,0,len, Charset.forName("UTF-8")));
        }
        input.close();

        System.out.println("Resp Code:"+con.getResponseCode());
        System.out.println("Resp Message:"+ con.getResponseMessage());

        return sb.toString();
    }

    /**
     *
     * @param strUrl 请求地址
     * @param params 请求参数
     * @param method 请求方法
     * @return  网络请求字符串
     * @throws Exception
     */
    public static String net(String strUrl, Map params,String method) throws Exception {
        HttpURLConnection conn = null;
        BufferedReader reader = null;
        String rs = null;
        try {
            StringBuffer sb = new StringBuffer();
            if(method==null || method.equals("GET")){
                strUrl = strUrl+"?"+urlencode(params);
            }
            URL url = new URL(strUrl);
            conn = (HttpURLConnection) url.openConnection();
            if(method==null || method.equals("GET")){
                conn.setRequestMethod("GET");
            }else{
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
            }
            conn.setRequestProperty("User-agent", userAgent);
            conn.setUseCaches(false);
            conn.setConnectTimeout(DEF_CONN_TIMEOUT);
            conn.setReadTimeout(DEF_READ_TIMEOUT);
            conn.setInstanceFollowRedirects(false);
            conn.connect();
            if (params!= null && method.equals("POST")) {
                try {
                    DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                    out.writeBytes(urlencode(params));
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
            InputStream is = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sb.append(strRead);
            }
            rs = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return rs;
    }

    //将map型转为请求参数型
    public static String urlencode(Map<String,Object>data) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry i : data.entrySet()) {
            try {
                sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue()+"","UTF-8")).append("&");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

    /**
     * 获取请求数据
     * @param is
     * @return
     */
    public static String getRequestData(InputStream is) {
        try {
            byte[] data = new byte[1024];
            int len =0;
            StringBuilder sb = new StringBuilder();
            while ((len=is.read(data))!= -1) {
                sb.append(new String(data,0,len));
            }
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    /**
     * 把文件读取成byte[]
     * @param filePath
     * @return
     */
    public static byte[] readFile(String filePath) {
        File file = new File(filePath);
        if(!file.exists()){
            throw new RuntimeException("文件不存在！"+filePath);
        }

        // 定义一个存放输入流的缓冲对象
        BufferedInputStream bis = null;

        // 定义一个输出流，相当StringBuffer（），会根据读取数据的大小，调整byte的数组长度
        ByteArrayOutputStream baos = new ByteArrayOutputStream(((int) file.length()));
        try {
            bis = new BufferedInputStream(new FileInputStream(filePath));

            int len = 0;
            int bufSize = 1024;
            byte[] buf = new byte[bufSize];
            while ((len = bis.read(buf,0,bufSize)) != -1) {
                baos.write(buf, 0, len);
            }

            byte[] buffer = baos.toByteArray();
            return buffer;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭所有的流
                if(baos!=null){
                    baos.close();
                }

                if(bis!=null){
                    bis.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * 读取文件字节流
     * @param filePath 文件路径
     * @return file bytes
     * @throws IOException 读取文件错误
     */
    public static byte[] readFileByBytes(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream(((int) file.length()));
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(file));
            int bufSize = 1024;
            byte[] buffer = new byte[bufSize];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, bufSize))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            bos.close();
        }
    }
}
